/**
 * dom 相关公共方法
 */
import config from '../config'

/**
 * 滚动是否平滑
 * 如果为 `'auto'` 则根据配置的平滑滚动距离调整，距离内平滑，距离外不平滑
 */
export type ScrollSmooth = boolean | 'auto'

/**
 * 滚动到指定位置
 * @param {Element} el 滚动区域
 * @param {number} [left=0]
 * @param {number} [top=0]
 * @param {boolean} [smooth = 'auto'] 是否平滑滚动， 'auto' 则根据滑动距离判断
 */
export function scrollTo(el: HTMLElement, left = el.scrollLeft, top = el.scrollTop, smooth: ScrollSmooth = 'auto') {
  if (!el) return

  if (el.scrollTo) {
    if (smooth === 'auto') {
      // 在平滑滚动距离范围内才平滑滚动
      smooth = Math.abs(el.scrollTop - top) <= config.scrollSmoothDistance
    }
    el.scrollTo({
      left,
      top,
      behavior: smooth ? 'smooth' : 'auto'
    })
  } else {
    el.scrollLeft = left
    el.scrollTop = top
  }
}

/**
 * 指定元素滚动到可视区域
 * @param {HTMLElement | string} el 目标元素或选择器
 * @param {HTMLElement} scroller 滚动区域
 * @param {boolean} [smooth = true] 是否平滑滚动
 */
export function scrollIntoView(
  el: HTMLElement | string,
  scroller?: HTMLElement,
  smooth = true,
  block: ScrollLogicalPosition = 'start'
) {
  if (typeof el === 'string') {
    el = document.querySelector(el) as HTMLElement
  }

  if (!el) return

  if (el.scrollIntoView) {
    el.scrollIntoView({ behavior: smooth ? 'smooth' : 'auto', block })
  } else if (scroller) {
    const { offsetLeft, offsetTop } = el
    scrollTo(scroller, offsetLeft, offsetTop, smooth)
  }
}

/** 获取浏览器滚动条宽度 */
export function getScrollbarWidth() {
  let width = 0
  const div = document.createElement('div')

  div.style.cssText =
    'position: absolute; top:-9999px; visibility: hidden; width: 100px; height: 100px; overflow-y: scroll'

  document.body.appendChild(div)

  width = div.offsetWidth - div.clientWidth

  div.parentElement?.removeChild(div)

  return width
}

/**
 * 强制回流
 * @description 用于处理浏览器渲染不正确
 */
export function forceReflow(el: HTMLElement) {
  if (!el) return

  const { style } = el

  style.opacity = '0.99'

  setTimeout(() => (style.opacity = '1'))
}

/** 查找最近的父节点 */
export function queryClosestSelector(el: HTMLElement, query: string) {
  if (!el || !query) return null

  const selectors = Array.from(document.querySelectorAll(query))

  let parent: HTMLElement | null = el.parentElement

  while (parent) {
    if (selectors.includes(parent)) return parent

    parent = parent.parentElement
  }

  return null
}

/** 节点是否匹配选择器 */
export function isElMatchSelector(el: HTMLElement, selector: string) {
  if (!el || !selector) return false

  const { parentElement: parent } = el

  // html 根节点
  if (!parent) {
    return queryClosestSelector(document.body, selector)
  }

  return Array.from(parent.querySelectorAll(selector)).includes(el)
}

/** 事件目标或节点是否可编辑 */
export function isElEditable(target?: EventTarget | Element | null) {
  const el = target as HTMLInputElement
  return el && ['input', 'textarea'].includes(el.tagName.toLowerCase() || '') && !el.disabled && !el.readOnly
}
